package paper.crawler;

import java.util.regex.*;
import java.util.Vector;
import java.util.Iterator;

import java.net.URL;

import java.io.InputStream;
import java.io.InputStreamReader;

public abstract class HTMLParser implements HillClimber{
    static Pattern completeURL = Pattern.compile("^[a-z]+://.*");
    static Pattern absoluteURL = Pattern.compile("/.*");

    static Pattern tag  = Pattern.compile("<[^>]*>");
    static Pattern href = Pattern.compile("<a[^>]*href=("+
                                          "([^ \n>]*)|" +
                                          "('[^' \n>]*')|" +
                                          "(\"[^\" \n>]*\")[^>]*>)",
                                          Pattern.CASE_INSENSITIVE) ;
    static Pattern eref = Pattern.compile("</a *>",
                                          Pattern.CASE_INSENSITIVE) ;
    int hopCount;
    Crawler c;

    /*
     * Override this function in to decide what to do with text that
     * has been found inside a URL. It is at present called after
     * linkRUL is called (should be the other way around!)
     */
    public void linkText(String x) {}
    /*
     * Fill this function in to decide what to do with a URL that has
     * been found. If the URL is to be followed up you shoudl eventually
     * call doURL.
     */
    public abstract void linkURL(String x);
    /*
     * Override this function in to decide what to do with text that
     * has been fond on the page. You can leave this empty.
     */
    public void otherText(String x) {}

    /*
     * Call this function to decide to follow up a URL. The higher quality,
     * the sooner the URL will be followed
     */
    protected void doURL(String url, double quality) {
        c.scheduleGlobalURL(url, hopCount, quality);
    }

    public void parse(String base, int hopCount, InputStream is, Crawler c) {
        this.c = c;
        this.hopCount= hopCount;
        try {
            char[] charBuffer = new char[4096];
            InputStreamReader isr = new InputStreamReader(is);
            StringBuilder sb = new StringBuilder();
            while (true) {                 // fixme: stream matching.
                int i = isr.read(charBuffer,0, 4096);
                if (i < 0 || sb.length() > 512000) {
                    break;
                }
                sb.append(charBuffer, 0, i);
            }
            Vector<String> links = new Vector();
            String absBase;
            int end = base.indexOf("/",7);
            if (end == -1) {
                base += "/";
                absBase = base;
            } else {
                absBase = base.substring(0,end+1);
                end = base.lastIndexOf("/");
                base = base.substring(0,end+1);
            }
            Matcher matchTag = tag.matcher(sb);
            Matcher matchRef = href.matcher(sb);
            Matcher matchEnd = eref.matcher(sb);
            boolean inLink = false;
            int last = 0;
            while (matchTag.find()) {
                int tagStart = matchTag.start();
                String skippedText = sb.substring(last, tagStart);
                last = matchTag.end();
                if (inLink) {
                    linkText(skippedText);
                } else {
                    otherText(skippedText);
                }
                if (matchRef.find(tagStart) && matchRef.start() == tagStart) {
                    inLink = true;
                    String link = matchRef.group(1);
                    if (link.startsWith("'") || link.startsWith("\"")) {
                        link = link.substring(1,link.length()-1);
                    }
                    if (link != null && !link.equals("")) {
                        if (completeURL.matcher(link).matches()) {
                            linkURL(link);
                        } else if (absoluteURL.matcher(link).matches()) {
                            linkURL(absBase + link);
                        } else {
                            linkURL(base + link);
                        }
                    }
                } else if (matchEnd.find(tagStart) && matchEnd.start() == tagStart) {
                    inLink = false;
                }
            }
        } catch (Exception e) {
            System.out.println("Shit... " + e);
        }
    }

}
